#pragma once

#include <iostream>
#include <functional>
#include <unordered_map>
#include <cassert>
#include <unistd.h>
#include <cerrno>
#include <cstring>
#include <vector>
#include "Sock.hpp"
#include "LogMessage.hpp"
#include "Epoll.hpp"
#include "serialization.hpp"
#include "calculator.hpp"

#define SPE "X" // 报文与报文之间以SPE为间隔
#define SPELEN strlen(SPE)

class Connection;
class EpollETServer;
using func_t = std::function<void(Connection *)>;

class Connection
{
public:
    Connection(int sock)
        : _sock(sock), _call_back(nullptr), _read_cb(nullptr), _write_cb(nullptr), _except_cb(nullptr)
    {
    }

    void MangeCallBack(func_t read, func_t write, func_t except)
    {
        _read_cb = read;
        _write_cb = write;
        _except_cb = except;
    }

public:
    int _sock;
    func_t _read_cb;
    func_t _write_cb;
    func_t _except_cb;

    std::string _recv_buffer; // 接受缓冲区
    std::string _send_buffer; // 发送缓冲区

    EpollETServer *_call_back;
};

class EpollETServer
{
    int globalsize = 20;
    int eventsize = 20;

public:
    EpollETServer(std::string ip = "0.0.0.0", uint16_t port = 8080)
        : _evesize(eventsize)
    {
        // 1.创建套接字
        _listensock = _sock.Socket();
        _sock.Bind(_listensock, ip, port);
        _sock.Listen(_listensock);

        // 2.创建epoll
        _epfd = Epoll::EpollCreate(globalsize);
        if (_epfd < 0)
        {
            LogMessage(Debug, "create epfd error");
            exit(1);
        }
        LogMessage(Debug, "create sock and epfd success, _listensock: %d  _epfd: %d", _listensock, _epfd);

        // 3.将_listensock加入_epfd中
        AddConnection(_listensock, std::bind(&EpollETServer::Accept, this, std::placeholders::_1), nullptr, nullptr);
        Epoll::EpollCtrl(_epfd, EPOLL_CTL_ADD, _listensock, EPOLLIN | EPOLLET);

        // 4.构建一个epoll_event缓冲区
        _events = new epoll_event[_evesize];
    }

    ~EpollETServer()
    {
        if (_listensock)
            close(_listensock);
        if (_epfd)
            close(_epfd);
        if (_events)
            delete[] _events;

        for (auto con : _sockandCon)
        {
            delete con.second;
        }
    }

    void AddConnection(int sock, func_t read, func_t write, func_t except)
    {
        bool ret = _sock.SetNonBlock(sock);
        Connection *con = new Connection(sock);
        assert(con != nullptr);
        con->MangeCallBack(read, write, except);
        con->_call_back = this;

        _sockandCon.insert(std::make_pair(sock, con));
    }

    void Accept(Connection *args)
    {
        while (true)
        {
            std::string ip;
            uint16_t port;
            int serversock = _sock.Accept(_listensock, &ip, &port);
            if (serversock >= 0)
            {
                // 将serversock交给epoll
                AddConnection(serversock, std::bind(&EpollETServer::Recver, this, std::placeholders::_1), std::bind(&EpollETServer::Sender, this, std::placeholders::_1), std::bind(&EpollETServer::Excepter, this, std::placeholders::_1));
                Epoll::EpollCtrl(_epfd, EPOLL_CTL_ADD, serversock, EPOLLIN | EPOLLET);
                LogMessage(Debug, "[%s, %d] link success", ip.c_str(), port);
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    LogMessage(Warning, "create serversock error, errno: %d, strerror: %s", errno, strerror(errno));
                    break;
                }
            }
        }
    }

    void LoopOnce(int timeout)
    {
        int n = Epoll::EpollWait(_epfd, _events, _evesize, timeout);
        if (n > 0)
        {
            // 读取成功
            for (int i = 0; i < n; i++)
            {
                int fd = _events[i].data.fd;
                int event = _events[i].events;
                if (event & EPOLLIN == 1)
                {
                    if (_sockandCon[fd] != nullptr && _sockandCon[fd]->_read_cb != nullptr)
                        _sockandCon[fd]->_read_cb(_sockandCon[fd]);
                }
                if (event & EPOLLOUT == 1)
                {
                    if (_sockandCon[fd] != nullptr && _sockandCon[fd]->_read_cb != nullptr)
                        _sockandCon[fd]->_write_cb(_sockandCon[fd]);
                }
            }
        }
        else if (n == 0)
        {
            LogMessage(Debug, "time out");
        }
        else
        {
            LogMessage(Warning, "epollwait error, errno: %d, strerror: %s", errno, strerror(errno));
        }

        PrintDebug();
    }

    void Recver(Connection *con)
    {
        while (true)
        {
            std::string buffer;
            int n = _sock.Revc(con->_sock, buffer);
            if (n > 0)
            {
                // 读取成功
                con->_recv_buffer += buffer;
                // LogMessage(Debug, "recv a message: %s", con->_recv_buffer.c_str());
            }
            else if (n == 0)
            {
                if (con == nullptr)
                    return;
                if (_sockandCon[con->_sock] == nullptr)
                    return;
                LogMessage(Debug, "you close, me too");
                Epoll::EpollCtrl(_epfd, EPOLL_CTL_DEL, con->_sock, 0);
                close(con->_sock);
                _sockandCon.erase(con->_sock);
                delete con;
                return;
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    LogMessage(Warning, "Recv error, errno: %d, strerror: %s", errno, strerror(errno));
                    break;
                }
            }
        }

        // 将读取好的数据交给分割成单个报文
        std::vector<std::string> v;
        GetCompletePacket(con->_recv_buffer, &v);
        for (auto e : v)
        {
            std::cout << e << std::endl;
        }
        // 向上交付，进行业务处理
        Handler(v);
    }

    void Handler(std::vector<std::string> &v)
    {
        // 将v中的数据反序列化
        //  2. 处理信息
        for (auto e : v)
        {
            Request rqt;
            rqt.Deserialization(e);
            Respond rpd = Compute(rqt);
            std::string res = rpd.Serialization();

            std::cout << res << std::endl;
        }
    }

    void Sender(Connection *con)
    {
    }

    void Excepter(Connection *con)
    {
        Epoll::EpollCtrl(_epfd, EPOLL_CTL_DEL, con->_sock, 0);
        close(con->_sock);
        _sockandCon.erase(con->_sock);
    }

    // 1+243X43&3X123
    void GetCompletePacket(std::string &str, std::vector<std::string> *reback)
    {
        while (true)
        {
            auto pos = str.find(SPE);
            if (pos == std::string::npos)
            {
                break;
            }
            (*reback).push_back(str.substr(0, pos));
            str.erase(0, pos + SPELEN);
        }
    }

    void Start()
    {
        while (true)
        {
            LoopOnce(1000);
        }
    }

    void PrintDebug()
    {
        std::cout << "epfd: ";
        for (auto eve : _sockandCon)
        {
            std::cout << eve.first << " ";
        }
        std::cout << std::endl;
    }

private:
    int _listensock;
    int _epfd;
    Sock _sock;
    std::unordered_map<int, Connection *> _sockandCon;
    epoll_event *_events;
    int _evesize;
};